package net.maxupeng.asm74.segment;

import net.maxupeng.asm74.antlr.ASM74Parser;

import java.util.ArrayList;
import java.util.List;

import static net.maxupeng.asm74.Compiler.evalExpr;
import static net.maxupeng.asm74.util.NumberUtil.str2int;

public class RODataSegment extends Segment {
    public RODataSegment(ASM74Parser.ProgContext progCtx) {
        super(progCtx);
    }

    public static List<RODataSegment> parse(List<ASM74Parser.ProgContext> progCtxs) {
        List<RODataSegment> rodatas = new ArrayList<>();

        RODataSegment rodata = new RODataSegment(null);
        for (ASM74Parser.ProgContext progCtx : progCtxs) {
            boolean isReadOnlyDataSegment = false;
            for (ASM74Parser.LineContext lineCtx : progCtx.line()) {
                if (isReadOnlyDataSegment && lineCtx.label() != null) {
                    rodata.ramLabelOffsetMap.put(lineCtx.label().ID().getText(), rodata.romSize);
                }

                if (lineCtx.cmd() != null) {
                    ASM74Parser.CmdContext cmdCtx = lineCtx.cmd();
                    String cmd = cmdCtx.getStart().getText();
                    if (cmd.equals(".segment")) {
                        isReadOnlyDataSegment = cmdCtx.STRING().getText().trim().replaceAll("^\"|\"$", "").toUpperCase().equals("RODATA");
                        if (isReadOnlyDataSegment) {
                            rodata = new RODataSegment(progCtx);
                            rodatas.add(rodata);
                        }
                    }

                    if (isReadOnlyDataSegment) {
                        if (cmd.equals(".byte")) {
                            List<Integer> bytes = new ArrayList<>();
                            for (int i = 0; i < cmdCtx.NUMBER().size(); i++) {
                                bytes.add(str2int(cmdCtx.NUMBER(i).getText()));
                            }
                            rodata.romSize += bytes.size();
                            rodata.ramSize += bytes.size();

                            for (Integer b : bytes) {
                                rodata.rom.add(b & 0xff);
                            }
                        } else if (cmd.equals("=")) {
                            int refAddr = evalExpr(cmdCtx.expr(), rodata.ramLabelOffsetMap);
                            rodata.ramLabelOffsetMap.put(lineCtx.label().ID().getText(), refAddr);
                        }
                    }
                }
            }
        }

        return rodatas;
    }
}